package br.ufrn.btest.tests.unit;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.Before;
import org.junit.Test;

import br.ufrn.btest.parser.Machine;
import br.ufrn.btest.parser.Operation;
import de.be4.classicalb.core.parser.BException;

public class OperationTest {
	
	
	private Operation operation;
	
	
	@Before
	public void setUp() {
		try {
			Machine machine = new Machine(new File("machines/Test.mch"));
			this.operation = machine.getOperation(0);
		} catch (BException e) {
			e.printStackTrace();
		}
	}
	
	
	
	@Test
	public void canGetOperationName() {
		String operationName = this.operation.getName();
		assertEquals("set_cab_consol_open_button_pressed", operationName);
	}
	
	
	
	@Test
	public void canGetOperationParameters() {
		List<String> expectedParameters = new ArrayList<String>();
		expectedParameters.add("pressed");
		
		assertTrue(expectedParameters.equals(operation.getParameters()));
	}
	
	
	
	@Test
	public void canGetOperationPrecondition() {
		String expectedPrecondition = "pressed : BOOL & ((pressed = TRUE) => (foo = FALSE))";
		String actualPrecondition = operation.getPrecondition().toString();
		
		assertEquals(expectedPrecondition, actualPrecondition);
	}
	
	
	
	@Test
	public void shouldGetMachineFromOperation() {
		assertEquals("Test", operation.getMachine().getName());
	}
	

	
	@Test
	public void shouldGetIfCommandVariables() {
		Machine machine = getMachineInstance("machines/IFMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedVariables = new HashSet<String>();
		expectedVariables.add("var1");
		expectedVariables.add("var2");
		
		Set<String> ifVariables = operationUnderTest.getIfCommandVariables();
		
		assertEquals(expectedVariables, ifVariables);
	}
	
	
	
	@Test
	public void shouldGetIfCommandConditions() {
		Machine machine = getMachineInstance("machines/IFMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedConditions = new HashSet<String>();
		expectedConditions.add("var1 = var2");
		
		Set<String> ifConditions = operationUnderTest.getConditionalCharacteristics();
		
		assertEquals(expectedConditions, ifConditions);
	}
	
	
	
	@Test
	public void shouldGetIfCommandConditionsInsideParallelSubstitution() {
		Machine machine = getMachineInstance("machines/exemplos_schneider/Registrar.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedConditions = new HashSet<String>();
		expectedConditions.add("nn : dom(marriage)");
		expectedConditions.add("nn : ran(marriage)");
		
		Set<String> ifConditions = operationUnderTest.getConditionalCharacteristics();
		
		assertEquals(expectedConditions, ifConditions);
	}

	
	
	@Test
	public void shouldGetIfElsifCommandVariables() {
		Machine machine = getMachineInstance("machines/IFELSEIFMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedVariables = new HashSet<String>();
		expectedVariables.add("var1");
		expectedVariables.add("var2");
		
		Set<String> ifVariables = operationUnderTest.getIfCommandVariables();
		
		assertEquals(expectedVariables, ifVariables);
	}
	
	
	
	@Test
	public void shouldGetIfElsifCommandConditions() {
		Machine machine = getMachineInstance("machines/IFELSEIFMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedConditions = new HashSet<String>();
		expectedConditions.add("var1 > var2");
		expectedConditions.add("var1 < var2");
		expectedConditions.add("var1 = var2");
		
		Set<String> ifConditions = operationUnderTest.getConditionalCharacteristics();
		
		assertEquals(expectedConditions, ifConditions);
	}
	
	
	
	@Test
	public void shouldGetCaseCommandVariables() {
		Machine machine = getMachineInstance("machines/CASEMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedVariables = new HashSet<String>();
		expectedVariables.add("var2");
		
		Set<String> ifVariables = operationUnderTest.getIfCommandVariables();
		
		assertEquals(expectedVariables, ifVariables);
	}
	
	
	
	@Test
	public void shouldGetCaseCommandConditions() {
		Machine machine = getMachineInstance("machines/CASEMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedConditions = new HashSet<String>();
		expectedConditions.add("var2 : {0}");
		
		Set<String> ifConditions = operationUnderTest.getConditionalCharacteristics();
		
		assertEquals(expectedConditions, ifConditions);
	}
	
	
	
	@Test
	public void shouldGetSelectCommandVariables() {
		Machine machine = getMachineInstance("machines/SELECTMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedVariables = new HashSet<String>();
		expectedVariables.add("var1");
		expectedVariables.add("var2");
		
		Set<String> ifVariables = operationUnderTest.getIfCommandVariables();
		
		assertEquals(expectedVariables, ifVariables);
	}
	
	
	
	@Test
	public void shouldGetSelectCommandConditions() {
		Machine machine = getMachineInstance("machines/SELECTMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedConditions = new HashSet<String>();
		expectedConditions.add("var1 > var2");
		expectedConditions.add("var1 < var2");
		expectedConditions.add("var1 = var2");
		
		Set<String> ifConditions = operationUnderTest.getConditionalCharacteristics();
		
		assertEquals(expectedConditions, ifConditions);
	}
	
	
	
	@Test
	public void shouldGetConditionsCommandFromMachineWithNoPrecondition() {
		Machine machine = getMachineInstance("machines/IFWithNoPrecondition.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		Set<String> expectedConditions = new HashSet<String>();
		expectedConditions.add("xx = 1");
		
		Set<String> ifConditions = operationUnderTest.getConditionalCharacteristics();
		
		assertEquals(expectedConditions, ifConditions);
	}
	
	
	
	@Test
	public void shouldReturnEmptyWhenGettingReturnVariablesForOperationWithoutReturn() {
		Machine machine = getMachineInstance("machines/OperationWithReturnMachine.mch");
		Operation operationUnderTest = machine.getOperation(0);

		List<String> returnVariables = operationUnderTest.getReturnVariables();
		
		assertTrue(returnVariables.isEmpty());
	}
	
	
	
	@Test
	public void shouldReturnListOfReturnVariablesWhenOperationHasOneReturnVariable() {
		Machine machine = getMachineInstance("machines/OperationWithReturnMachine.mch");
		Operation operationUnderTest = machine.getOperation(1);

		List<String> expectedReturnVariables = new ArrayList<String>();
		expectedReturnVariables.add("xx");
		
		List<String> returnVariables = operationUnderTest.getReturnVariables();
		
		assertEquals(expectedReturnVariables, returnVariables);
	}
	
	
	
	@Test
	public void shouldReturnListOfReturnVariablesWhenOperationHasManyReturnVariable() {
		Machine machine = getMachineInstance("machines/OperationWithReturnMachine.mch");
		Operation operationUnderTest = machine.getOperation(2);

		List<String> expectedReturnVariables = new ArrayList<String>();
		expectedReturnVariables.add("aa");
		expectedReturnVariables.add("bb");
		expectedReturnVariables.add("cc");
		
		List<String> returnVariables = operationUnderTest.getReturnVariables();
		
		assertEquals(expectedReturnVariables, returnVariables);
	}
	
	
	
	private Machine getMachineInstance(String path) {
		Machine machine;
		try {
			machine = new Machine(new File(path));
		} catch (BException e) {
			machine = null;
		}
		return machine;
	}

}
	